package lexico10.Model;
import java.util.*;

/**
 *
 * @author Fábio
 */
public class Automato {
    //Constantes
    private int qtdFinais = 13;
    private int qtdErros = 5;
    private int qtdEstados = 36;
    private int qtdSimbolos = 17;
    private int invalido = -1;
    private int estadoInicial=0;
    
    ArrayList<String> vetorSSimbolos = new ArrayList<String> ();
    int[] listaFinais = {2, 6, 9, 13, 17, 22, 24, 25, 26, 28, 30, 32, 34};
    int[] listaErros = {4, 11, 14, 18, 35};
    char[] vetorSimbolos=new char[qtdSimbolos];
    int[][]matADJ = new int[qtdEstados][qtdSimbolos];
    private int posInicialCadeia=0;
    private int posFinalCadeia=0;
    private int linha=1;
    private int estadoAtual, estadoFuturo;

    public Automato(){
        setPosFinalCadeia(0);
        setPosInicialCadeia(0);
        gerarVetorSimbolos();
        trasicoes();
    }
    public void getEstadosFinais(){
        for(int i=0; i<qtdFinais;i++)
        System.out.println("Estados Finais: "+ listaFinais[i]);
    }
    public int getPosInicialCadeia() {
        return posInicialCadeia;
    }

    public void setPosInicialCadeia(int posInicialCadeia) {
        this.posInicialCadeia = posInicialCadeia;
    }

    public int getPosFinalCadeia() {
        return posFinalCadeia;
    }

    public void setPosFinalCadeia(int posFinalCadeia) {
        this.posFinalCadeia = posFinalCadeia;
    }

    public int getLinha() {
        return linha;
    }

    public void setLinha(int linha) {
        this.linha = linha;
    }

    public int getEstadoAtual() {
        return estadoAtual;
    }

    public void setEstadoAtual(int estadoAtual) {
        this.estadoAtual = estadoAtual;
    }

    public int getEstadoFuturo() {
        return estadoFuturo;
    }

    public void setEstadoFuturo(int estadoFuturo) {
        this.estadoFuturo = estadoFuturo;
    }

public void setTrasicoes(int origem, char entrada, int destino){
          matADJ[origem][buscaPosicaoSimbolo(verificaTipoCaracter(entrada))]=destino;
}    
public void trasicoes(){
    //Inicializa a matriz com um estado invalido
    for(int i=0; i <qtdEstados; i++){
        for(int j=0; j<qtdSimbolos; j++)
            matADJ[i][j]=invalido;
    }
    //Formato: origem entrada destino
    //Consumindo espaços no estado inicial;
    setTrasicoes(0, ' ', 0);
    setTrasicoes(0, '\n', 0);

    //Identificador
    setTrasicoes(0, 'l', 1);//qualquer letra
    setTrasicoes(1, 'l', 1);//qualquer letra
    setTrasicoes(1, '1', 1);//qualquer numero
    setTrasicoes(1, '_', 1);//_
    setTrasicoes(1, ' ', 2);//espaço
    setTrasicoes(1, ';', 2);//delimitador
    setTrasicoes(1, '[', 2);//delimitador
    setTrasicoes(1, '+', 2);//operador
    setTrasicoes(1, '*', 2);//operador
    setTrasicoes(1, '/', 2);//operador
    setTrasicoes(1, '\n', 2);//\n
    setTrasicoes(1, '!', 2);
    setTrasicoes(1, '&', 2);
    setTrasicoes(1, '.', 2);
    setTrasicoes(1, '|', 2);
    setTrasicoes(1, '@', 3);//qualquer simbolo dos nao usados
    setTrasicoes(1, '"', 3);
    setTrasicoes(1, '\'', 3);//aspas simples
    setTrasicoes(3, 'l', 3);//qualquer letra
    setTrasicoes(3, '1', 3);//qualquer numero
    setTrasicoes(3, '_', 3);//_
    setTrasicoes(3, '@', 3);
    setTrasicoes(3, '\'', 3);//aspas simples
    setTrasicoes(3, '!', 4);
    setTrasicoes(3, '&', 4);
    setTrasicoes(3, '.', 4); 
    setTrasicoes(3, '|', 4);
    setTrasicoes(3, '"', 3);
    setTrasicoes(3, ' ', 4);//espaço
    setTrasicoes(3, '[', 4);//delimitador
    setTrasicoes(3, ';', 4);//delimitador
    setTrasicoes(3, '+', 4);//operador
    setTrasicoes(3, '*', 4);//operador
    setTrasicoes(3, '/', 4);//operador
    setTrasicoes(3, '\n', 4);//\n
    
    //Digito
    setTrasicoes(0, '1', 5);
    setTrasicoes(5, '1', 5);
    setTrasicoes(5, ';', 6);//delimitador
    setTrasicoes(5, '[', 6);//delimitador
    setTrasicoes(5, ' ', 6);//espaço
    setTrasicoes(5, '+', 6);//operador
    setTrasicoes(5, '*', 6);//operador
    setTrasicoes(5, '/', 6);//operador
    setTrasicoes(5, '\n', 6);//\n
    setTrasicoes(5, '&', 6);
    setTrasicoes(5, '!', 6);
    setTrasicoes(5, '|', 6);
    setTrasicoes(5, '.', 7);
    setTrasicoes(5, '@', 10);
    setTrasicoes(5, '"', 10);
    setTrasicoes(5, '\'', 10);
    setTrasicoes(7, '1', 8);
    setTrasicoes(7, 'a',10);
    setTrasicoes(7, '+',10);
    setTrasicoes(7, '*',10);
    setTrasicoes(7, '/',10);
    setTrasicoes(7, '@',10);
    setTrasicoes(7, '!',10);
    setTrasicoes(7, '"',10);
    setTrasicoes(7, '&',10);
    setTrasicoes(7, '\'',10);
    setTrasicoes(7, '.',10);
    setTrasicoes(7, '_',10);
    setTrasicoes(7, '|',10);
    setTrasicoes(7, ' ',11);
    setTrasicoes(7, ';',11);
    setTrasicoes(7, '\n',11);//\n
    setTrasicoes(8, '1', 8);
    setTrasicoes(8, ' ', 9);//espaço
    setTrasicoes(8, ';', 9);//delimitador
    setTrasicoes(8, '[', 9);//delimitador
    setTrasicoes(8, '+', 9);//operador
    setTrasicoes(8, '*', 9);//operador    
    setTrasicoes(8, '/', 9);//operador
    setTrasicoes(8, '\n',9);//\n
    setTrasicoes(8, '!',9);
    setTrasicoes(8, '&',9);
    setTrasicoes(8, '|',9);
    setTrasicoes(8, 'a',10);
    setTrasicoes(8, '@',10);
    setTrasicoes(8, '"',10);
    setTrasicoes(8, '\'',10);
    setTrasicoes(8, '.',10);
    setTrasicoes(8, '_',10);
    setTrasicoes(10, 'a',10);
    setTrasicoes(10, '1',10);
    setTrasicoes(10, '@',10);
    setTrasicoes(10, '"',10);
    setTrasicoes(10, '\'',10);
    setTrasicoes(10, '.',10);
    setTrasicoes(10, '_',10);
    setTrasicoes(10, '!',11);
    setTrasicoes(10, '&',11);
    setTrasicoes(10, '|',11);
    setTrasicoes(10, ' ',11);
    setTrasicoes(10, ';',11);
    setTrasicoes(10, '[',11);
    setTrasicoes(10, '+',11);
    setTrasicoes(10, '*',11);
    setTrasicoes(10, '/',11);
    setTrasicoes(10, '\n',11);//\n

    //cadeia Constante
    setTrasicoes(0, '"', 12);
    setTrasicoes(12, 'a', 12);
    setTrasicoes(12, '1', 12);
    setTrasicoes(12, '[', 12);
    setTrasicoes(12, ';', 12);
    setTrasicoes(12, '+', 12);
    setTrasicoes(12, '*', 12);
    setTrasicoes(12, '/', 12);
    setTrasicoes(12, '@', 12);
    setTrasicoes(12, '!', 12);
    setTrasicoes(12, '&', 12);
    setTrasicoes(12, '\'', 12);
    setTrasicoes(12, '.', 12);
    setTrasicoes(12, '_', 12);
    setTrasicoes(12, '|', 12);
    setTrasicoes(12, ' ', 12);
    setTrasicoes(12, '"', 13);
    setTrasicoes(12, '\n', 14);
     
     //Caractere Constante
    setTrasicoes(0, '\'', 15);
    setTrasicoes(15, 'a', 16);
    setTrasicoes(15, '1', 16);
    setTrasicoes(15, '[', 16);
    setTrasicoes(15, ';', 16);
    setTrasicoes(15, '+', 16);
    setTrasicoes(15, '*', 16);
    setTrasicoes(15, '/', 16);
    setTrasicoes(15, '@', 16);
    setTrasicoes(15, ' ', 16);
    setTrasicoes(15, '!', 16);
    setTrasicoes(15, '"', 16);
    setTrasicoes(15, '&', 16);
    setTrasicoes(15, '.', 16);
    setTrasicoes(15, '_', 16);
    setTrasicoes(15, '|', 16);  
    setTrasicoes(15, '\n', 18);
    setTrasicoes(15, '\'', 18);
    setTrasicoes(16, '\'', 17);
    setTrasicoes(16, 'a', 18);
    setTrasicoes(16, '1', 18);
    setTrasicoes(16, '[', 18);
    setTrasicoes(16, ';', 18);
    setTrasicoes(16, '+', 18);
    setTrasicoes(16, '*', 18);
    setTrasicoes(16, '/', 18);
    setTrasicoes(16, '@', 18);
    setTrasicoes(16, ' ', 18);
    setTrasicoes(16, '!', 18);
    setTrasicoes(16, '"', 18);
    setTrasicoes(16, '&', 18);
    setTrasicoes(16, '.', 18);
    setTrasicoes(16, '_', 18);
    setTrasicoes(16, '|', 18);
    setTrasicoes(16, '\n', 18);
    
    //Comentarios de linha e bloco, +, -, =, <, >, /, *, ++,-- e derivados
    setTrasicoes(0, '+', 19);
    setTrasicoes(0, '/', 19);
    setTrasicoes(0, '*', 19);
    setTrasicoes(0, '.', 19);
    setTrasicoes(19, '*', 20);
    setTrasicoes(19, '/', 23);
    setTrasicoes(19, '+', 25);
    //operador simples
    setTrasicoes(19, ' ', 26);
    //comentario de bloco
    setTrasicoes(20, 'a', 20);
    setTrasicoes(20, '1', 20);
    setTrasicoes(20, '[', 20);
    setTrasicoes(20, ';', 20);
    setTrasicoes(20, '+', 20);
    setTrasicoes(20, '@', 20);
    setTrasicoes(20, ' ', 20);
    setTrasicoes(20, '!', 20);
    setTrasicoes(20, '"', 20);
    setTrasicoes(20, '&', 20);
    setTrasicoes(20, '.', 20);
    setTrasicoes(20, '_', 20);
    setTrasicoes(20, '|', 20);
    setTrasicoes(20, '\'', 20);
    setTrasicoes(20, '*', 21);
    setTrasicoes(21, 'a', 20);
    setTrasicoes(21, '1', 20);
    setTrasicoes(21, '[', 20);
    setTrasicoes(21, ';', 20);
    setTrasicoes(21, '+', 20);
    setTrasicoes(21, '@', 20);
    setTrasicoes(21, ' ', 20);
    setTrasicoes(21, '!', 20);
    setTrasicoes(21, '"', 20);
    setTrasicoes(21, '&', 20);
    setTrasicoes(21, '.', 20);
    setTrasicoes(21, '_', 20);
    setTrasicoes(21, '|', 20);
    setTrasicoes(21, '\'', 20);
    setTrasicoes(21, '*', 21);
    setTrasicoes(21, '/', 22);
    //comentario de linha
    setTrasicoes(23, 'a', 23);
    setTrasicoes(23, '1', 23);
    setTrasicoes(23, '[', 23);
    setTrasicoes(23, ';', 23);
    setTrasicoes(23, '+', 23);
    setTrasicoes(23, '@', 23);
    setTrasicoes(23, ' ', 23);
    setTrasicoes(23, '!', 23);
    setTrasicoes(23, '"', 23);
    setTrasicoes(23, '&', 23);
    setTrasicoes(23, '.', 23);
    setTrasicoes(23, '_', 23);
    setTrasicoes(23, '|', 23);
    setTrasicoes(23, '\'', 23);
    setTrasicoes(23, '*', 23);
    setTrasicoes(23, '/', 23);
    setTrasicoes(23, '\n', 24);

    //!=
    setTrasicoes(0, '!', 27);
    setTrasicoes(27, '=', 28);
    setTrasicoes(27, 'a', 33);
    setTrasicoes(27, '1', 33);
    setTrasicoes(27, '@', 33);
    setTrasicoes(27, '"', 33);
    setTrasicoes(27, '_', 33);
    setTrasicoes(27, '\'', 33);  
    setTrasicoes(27, '|', 35); 
    setTrasicoes(27, '!', 35);       
    setTrasicoes(27, '&', 35);
    setTrasicoes(27, ' ', 35);
    setTrasicoes(27, '[', 35);
    setTrasicoes(27, ';', 35);
    setTrasicoes(27, '\n',35);
    setTrasicoes(27, '*', 35);
    setTrasicoes(27, '/', 35); 
    setTrasicoes(27, '.', 35);
    
    //&&
    setTrasicoes(0, '&', 31);
    setTrasicoes(31, '&', 32);
    setTrasicoes(31, 'a', 33);
    setTrasicoes(31, '1', 33);
    setTrasicoes(31, '@', 33);
    setTrasicoes(31, '"', 33);
    setTrasicoes(31, '_', 33);
    setTrasicoes(31, '\'', 33);
    setTrasicoes(31, '!', 35);
    setTrasicoes(31, '|', 35);
    setTrasicoes(31, ' ', 35);
    setTrasicoes(31, '[', 35);
    setTrasicoes(31, ';', 35);
    setTrasicoes(31, '\n',35);
    setTrasicoes(31, '+', 35);
    setTrasicoes(31, '*', 35);
    setTrasicoes(31, '/', 35); 
    setTrasicoes(31, '.', 35);
        
    //||
    setTrasicoes(0, '|', 29);
    setTrasicoes(29, '|', 30);
    setTrasicoes(29, 'a', 33);
    setTrasicoes(29, '1', 33);
    setTrasicoes(29, '@', 33);
    setTrasicoes(29, '"', 33);
    setTrasicoes(29, '_', 33);
    setTrasicoes(29, '\'', 33);
    setTrasicoes(29, ' ', 35);
    setTrasicoes(29, '[', 35);
    setTrasicoes(29, ';', 35);
    setTrasicoes(29, '\n',35);
    setTrasicoes(29, '+', 35);
    setTrasicoes(29, '*', 35);
    setTrasicoes(29, '/', 35);    
    setTrasicoes(29, '&', 35);
    setTrasicoes(29, '.', 35);
    setTrasicoes(29, '!', 35);
    
    //tratamento de erro operador duplos
    setTrasicoes(33, 'a', 33);
    setTrasicoes(33, '1', 33);
    setTrasicoes(33, '@', 33);
    setTrasicoes(33, '"', 33);
    setTrasicoes(33, '_', 33);
    setTrasicoes(33, '\'', 33);
    
    setTrasicoes(33, '|', 35);
    setTrasicoes(33, '&', 35);
    setTrasicoes(33, '!', 35);
    setTrasicoes(33, ' ', 35);
    setTrasicoes(33, '[', 35);
    setTrasicoes(33, ';', 35);
    setTrasicoes(33, '\n',35);
    setTrasicoes(33, '+', 35);
    setTrasicoes(33, '*', 35);
    setTrasicoes(33, '/', 35);    
    setTrasicoes(33, '.', 35);
    
    //Delimitadores
    setTrasicoes(0, '[', 34);
    setTrasicoes(0, ';', 34);
    
    //ERRO
    setTrasicoes(0, '@', 33);
    setTrasicoes(0, '_', 33);
}  
public char verificaTipoCaracter(char entrada){
        if (Character.isLetter(entrada)==true)    
            return '0';  //letra
            else if(Character.isDigit(entrada)==true)
                return '1';//numero
                else if((entrada==(char)40)||(entrada==(char)41)||(entrada==(char)44)||(entrada==(char)91)||(entrada==(char)93)||(entrada==(char)123)||(entrada==(char)125))
                    return '2';//delimitador
                    else if((entrada==(char)43)||(entrada==(char)45)||(entrada==(char)60)||(entrada==(char)61)||(entrada==(char)62))
                        return '3';//operadores simples
                        else if((entrada==(char)35)||(entrada==(char)36)||(entrada==(char)37)||(entrada==(char)58)||(entrada==(char)63)||(entrada==(char)64)||(entrada==(char)92)||(entrada==(char)94)||(entrada==(char)96||(entrada==(char)126)))
                            return '4';
                            else 
                                return entrada;//simbolo
                                
}
public void printMatriz(){
      for(int i=0; i <qtdEstados; i++){
        System.out.println("\n"); 
        
        for(int j=0; j<qtdSimbolos; j++)
            System.out.println(matADJ[i][j]);
      }
}
public void gerarVetorSimbolos(){
    vetorSimbolos[0] = (char)48;//letra
    vetorSimbolos[1] = (char)49;//numero
    vetorSimbolos[2] = (char)50;//delimitador
    vetorSimbolos[3] = (char)51;//operador
    vetorSimbolos[4] = (char)52;//simbolos nao usados
    vetorSimbolos[5] = (char)32;//espaço
    vetorSimbolos[6] = (char)33;//!
    vetorSimbolos[7] = (char)34;//"
    vetorSimbolos[8] = (char)38;//&
    vetorSimbolos[9] = (char)39;//'
    vetorSimbolos[10] = (char)46;//.
    vetorSimbolos[11] = (char)95;//_
    vetorSimbolos[12] = (char)124;//|
    vetorSimbolos[13] = (char)59;//;
    vetorSimbolos[14] = (char)10;//\n
    vetorSimbolos[15] = (char)42;///
    vetorSimbolos[16] = (char)47;//*
}
public int buscaPosicaoSimbolo(char simb){
    for(int i = 0; i < qtdSimbolos; i++){
       //System.out.println("vetor simbolos[" + i + "] "+ vetorSimbolos[i]); 
       if(vetorSimbolos[i]==simb)
           return i;      
   }
   return -1;
}
public boolean verificarEstadoFinal(int estadoAtual){
   boolean ok=false;
   for(int i = 0; i<qtdFinais; i++){
       if(listaFinais[i]==estadoAtual)
       {
           ok = true;
       }
    }
   return ok;
}
public boolean verificarEstadoErro(int estadoAtual){
   boolean erro=false;
   for(int i = 0; i<qtdErros; i++){
       if(listaErros[i]==estadoAtual)
       {
           erro = true;
       }
    }
   return erro;
}
public boolean run(String cadeia){    
    if((getPosInicialCadeia()==getPosFinalCadeia())&&(getPosFinalCadeia()>0))
        setPosInicialCadeia(getPosFinalCadeia()+1);
        else if ((getEstadoAtual()==23)||(getEstadoAtual()==25)||(getEstadoAtual()==26)||(getEstadoAtual()==28)||(getEstadoAtual()==30)||(getEstadoAtual()==32))
            setPosInicialCadeia(getPosFinalCadeia()+1);
            else
                setPosInicialCadeia(getPosFinalCadeia()); 
    setEstadoAtual(estadoInicial);
    for(int i = posInicialCadeia; i<cadeia.length();i++){  
        setPosFinalCadeia(i);
        if(i-1 != -1){
            if(cadeia.charAt(i-1)=='\n')
                setLinha(getLinha()+1);
        }
        if(matADJ[getEstadoAtual()][buscaPosicaoSimbolo(verificaTipoCaracter(cadeia.charAt(i)))]==invalido){
            setEstadoFuturo(getEstadoAtual());
            }else{
                if(0==matADJ[getEstadoAtual()][buscaPosicaoSimbolo(verificaTipoCaracter(cadeia.charAt(i)))])
                posInicialCadeia++;
                setEstadoFuturo(matADJ[getEstadoAtual()][buscaPosicaoSimbolo(verificaTipoCaracter(cadeia.charAt(i)))]);
                setEstadoAtual(getEstadoFuturo());
        }
        if(verificarEstadoFinal(getEstadoAtual())){
            setPosFinalCadeia(i);
            System.out.println("-----");
            return true;
        }
        if(verificarEstadoErro(getEstadoAtual())){
            return false;
        }
//        if(getEstadoAtual()==35||getEstadoAtual()==4)
//            return false;
        }
    return false;
}
}
